package org.cybzacg.encryption.annotations.processor;

import org.cybzacg.encryption.annotations.Encrypt;
import org.cybzacg.encryption.annotations.Decrypt;
import org.cybzacg.encryption.annotations.Sign;
import org.cybzacg.encryption.annotations.Verify;
import org.cybzacg.encryption.context.EncryptionContext;
import org.cybzacg.encryption.model.EncryptionResult;
import org.cybzacg.encryption.factory.EncryptorFactory;
import org.cybzacg.encryption.core.Encryptor;
import org.cybzacg.encryption.exception.EncryptionException;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 注解处理器
 * 处理加密相关的注解，实现自动加密/解密功能
 *
 * @author encryption team
 * @version 1.0
 */
public class AnnotationProcessor {

    // 注解处理器缓存
    private static final Map<Class<?>, FieldProcessor> fieldProcessors = new ConcurrentHashMap<>();
    private static final Map<Class<?>, MethodProcessor> methodProcessors = new ConcurrentHashMap<>();

    // 默认配置
    private static final boolean DEFAULT_CACHE_ENABLED = true;
    private static final boolean DEFAULT_MONITORING_ENABLED = true;
    private static final long DEFAULT_TIMEOUT = 15000;

    /**
     * 处理对象的加密注解
     *
     * @param target 目标对象
     * @param context 加密上下文
     * @return 处理结果
     */
    public static ProcessingResult processEncryption(Object target, EncryptionContext context) {
        if (target == null) {
            return ProcessingResult.success("Target object is null");
        }

        try {
            Class<?> targetClass = target.getClass();
            FieldProcessor fieldProcessor = getFieldProcessor(targetClass);
            return fieldProcessor.processEncryption(target, context);
        } catch (Exception e) {
            return ProcessingResult.failure("Failed to process encryption: " + e.getMessage());
        }
    }

    /**
     * 处理对象的解密注解
     *
     * @param target 目标对象
     * @param context 加密上下文
     * @return 处理结果
     */
    public static ProcessingResult processDecryption(Object target, EncryptionContext context) {
        if (target == null) {
            return ProcessingResult.success("Target object is null");
        }

        try {
            Class<?> targetClass = target.getClass();
            FieldProcessor fieldProcessor = getFieldProcessor(targetClass);
            return fieldProcessor.processDecryption(target, context);
        } catch (Exception e) {
            return ProcessingResult.failure("Failed to process decryption: " + e.getMessage(), e);
        }
    }

    /**
     * 处理方法的加密注解
     *
     * @param target 目标对象
     * @param methodName 方法名
     * @param args 方法参数
     * @param context 加密上下文
     * @return 处理结果
     */
    public static ProcessingResult processMethodEncryption(Object target, String methodName,
                                                          Object[] args, EncryptionContext context) {
        if (target == null) {
            return ProcessingResult.success("Target object is null");
        }

        try {
            Class<?> targetClass = target.getClass();
            MethodProcessor methodProcessor = getMethodProcessor(targetClass);
            return methodProcessor.processEncryption(target, methodName, args, context);
        } catch (Exception e) {
            return ProcessingResult.failure("Failed to process method encryption: " + e.getMessage(), e);
        }
    }

    /**
     * 处理方法的解密注解
     *
     * @param target 目标对象
     * @param methodName 方法名
     * @param args 方法参数
     * @param context 加密上下文
     * @return 处理结果
     */
    public static ProcessingResult processMethodDecryption(Object target, String methodName,
                                                            Object[] args, EncryptionContext context) {
        if (target == null) {
            return ProcessingResult.success("Target object is null");
        }

        try {
            Class<?> targetClass = target.getClass();
            MethodProcessor methodProcessor = getMethodProcessor(targetClass);
            return methodProcessor.processDecryption(target, methodName, args, context);
        } catch (Exception e) {
            return ProcessingResult.failure("Failed to process method decryption: " + e.getMessage(), e);
        }
    }

    /**
     * 获取字段处理器
     */
    private static FieldProcessor getFieldProcessor(Class<?> targetClass) {
        return fieldProcessors.computeIfAbsent(targetClass, k -> new FieldProcessor(targetClass));
    }

    /**
     * 获取方法处理器
     */
    private static MethodProcessor getMethodProcessor(Class<?> targetClass) {
        return methodProcessors.computeIfAbsent(targetClass, k -> new MethodProcessor(targetClass));
    }

    /**
     * 清除处理器缓存
     */
    public static void clearCache() {
        fieldProcessors.clear();
        methodProcessors.clear();
    }

    /**
     * 获取缓存大小
     */
    public static int getCacheSize() {
        return fieldProcessors.size() + methodProcessors.size();
    }

    /**
     * 字段处理器
     */
    private static class FieldProcessor {

        private final Class<?> targetClass;
        private final Map<String, Field> encryptFields = new HashMap<>();
        private final Map<String, Field> decryptFields = new HashMap<>();
        private final Map<String, Field> signFields = new HashMap<>();
        private final Map<String, Field> verifyFields = new HashMap<>();

        public FieldProcessor(Class<?> targetClass) {
            this.targetClass = targetClass;
            scanFields();
        }

        /**
         * 扫描字段注解
         */
        private void scanFields() {
            Field[] fields = targetClass.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);

                if (field.isAnnotationPresent(Encrypt.class)) {
                    encryptFields.put(field.getName(), field);
                }

                if (field.isAnnotationPresent(Decrypt.class)) {
                    decryptFields.put(field.getName(), field);
                }

                if (field.isAnnotationPresent(Sign.class)) {
                    signFields.put(field.getName(), field);
                }

                if (field.isAnnotationPresent(Verify.class)) {
                    verifyFields.put(field.getName(), field);
                }
            }
        }

        /**
         * 处理加密
         */
        public ProcessingResult processEncryption(Object target, EncryptionContext context) {
            List<String> processedFields = new ArrayList<>();
            List<String> failedFields = new ArrayList<>();

            for (Map.Entry<String, Field> entry : encryptFields.entrySet()) {
                try {
                    Field field = entry.getValue();
                    Object value = field.get(target);

                    if (value != null) {
                        Encrypt encryptAnnotation = field.getAnnotation(Encrypt.class);
                        byte[] encryptedData = encryptValue(value, encryptAnnotation, context);

                        // 如果字段类型是byte[]，直接设置
                        if (field.getType() == byte[].class) {
                            field.set(target, encryptedData);
                        } else {
                            // 其他类型转换为Base64字符串
                            String base64Value = Base64.getEncoder().encodeToString(encryptedData);
                            field.set(target, base64Value);
                        }

                        processedFields.add(entry.getKey());
                    }
                } catch (Exception e) {
                    failedFields.add(entry.getKey() + ": " + e.getMessage());
                }
            }

            if (failedFields.isEmpty()) {
                return ProcessingResult.success("Encrypted " + processedFields.size() + " fields");
            } else {
                return ProcessingResult.failure("Failed to encrypt fields: " + String.join(", ", failedFields));
            }
        }

        /**
         * 处理解密
         */
        public ProcessingResult processDecryption(Object target, EncryptionContext context) {
            List<String> processedFields = new ArrayList<>();
            List<String> failedFields = new ArrayList<>();

            for (Map.Entry<String, Field> entry : decryptFields.entrySet()) {
                try {
                    Field field = entry.getValue();
                    Object value = field.get(target);

                    if (value != null) {
                        Decrypt decryptAnnotation = field.getAnnotation(Decrypt.class);
                        byte[] decryptedData;

                        // 如果字段类型是byte[]，直接处理
                        if (field.getType() == byte[].class) {
                            decryptedData = decryptValue((byte[]) value, decryptAnnotation, context);
                        } else {
                            // 其他类型从Base64字符串转换
                            String base64Value = value.toString();
                            decryptedData = Base64.getDecoder().decode(base64Value);
                        }

                        field.set(target, decryptedData);
                        processedFields.add(entry.getKey());
                    }
                } catch (Exception e) {
                    failedFields.add(entry.getKey() + ": " + e.getMessage());
                }
            }

            if (failedFields.isEmpty()) {
                return ProcessingResult.success("Decrypted " + processedFields.size() + " fields");
            } else {
                return ProcessingResult.failure("Failed to decrypt fields: " + String.join(", ", failedFields));
            }
        }

        /**
         * 加密值
         */
        private byte[] encryptValue(Object value, Encrypt annotation, EncryptionContext context) {
            try {
                // 创建加密器
                Encryptor encryptor = createEncryptor(annotation, context);

                // 转换为字节数组
                byte[] data;
                if (value instanceof byte[]) {
                    data = (byte[]) value;
                } else if (value instanceof String) {
                    data = ((String) value).getBytes();
                } else {
                    // 序列化对象
                    data = serializeObject(value);
                }

                // 执行加密
                EncryptionResult result = encryptor.encrypt(data,  context);
                return result.isSuccess() ? result.getData() : null;

            } catch (Exception e) {
                throw new EncryptionException("Failed to encrypt value", e);
            }
        }

        /**
         * 解密值
         */
        private byte[] decryptValue(byte[] encryptedData, Decrypt annotation, EncryptionContext context) {
            try {
                // 创建加密器
                Encryptor encryptor = createEncryptor(annotation, context);

                // 执行解密
                EncryptionResult result = encryptor.decrypt(encryptedData,  context);
                return result.isSuccess() ? result.getData() : null;

            } catch (Exception e) {
                throw new EncryptionException("Failed to decrypt value", e);
            }
        }

        /**
         * 创建加密器
         */
        private Encryptor createEncryptor(Object annotation, EncryptionContext context) {
            if (annotation instanceof Encrypt) {
                Encrypt encrypt = (Encrypt) annotation;
                return EncryptorFactory.getInstance().createEncryptor(encrypt.algorithm(), context);
            } else if (annotation instanceof Decrypt) {
                Decrypt decrypt = (Decrypt) annotation;
                return EncryptorFactory.getInstance().createEncryptor(decrypt.algorithm(), context);
            } else if (annotation instanceof Sign) {
                Sign sign = (Sign) annotation;
                return EncryptorFactory.getInstance().createEncryptor(sign.algorithm(), context);
            } else if (annotation instanceof Verify) {
                Verify verify = (Verify) annotation;
                return EncryptorFactory.getInstance().createEncryptor(verify.algorithm(), context);
            }
            throw new IllegalArgumentException("Unsupported annotation type: " + annotation.getClass());
        }

        /**
         * 序列化对象
         */
        private byte[] serializeObject(Object obj) {
            // 简化实现：使用Java序列化
            // 实际应用中可以使用更高效的序列化方式
            try {
                java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
                java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
                oos.writeObject(obj);
                oos.close();
                return baos.toByteArray();
            } catch (Exception e) {
                throw new EncryptionException("Failed to serialize object", e);
            }
        }
    }

    /**
     * 方法处理器
     */
    private static class MethodProcessor {

        private final Class<?> targetClass;
        private final Map<String, Method> encryptMethods = new HashMap<>();
        private final Map<String, Method> decryptMethods = new HashMap<>();

        public MethodProcessor(Class<?> targetClass) {
            this.targetClass = targetClass;
            scanMethods();
        }

        /**
         * 扫描方法注解
         */
        private void scanMethods() {
            Method[] methods = targetClass.getDeclaredMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(Encrypt.class)) {
                    encryptMethods.put(method.getName(), method);
                }

                if (method.isAnnotationPresent(Decrypt.class)) {
                    decryptMethods.put(method.getName(), method);
                }
            }
        }

        /**
         * 处理加密
         */
        public ProcessingResult processEncryption(Object target, String methodName,
                                                   Object[] args, EncryptionContext context) {
            Method method = encryptMethods.get(methodName);
            if (method == null) {
                return ProcessingResult.success("No encryption annotation found for method: " + methodName);
            }

            try {
                // 处理方法参数的加密
                Object[] processedArgs = processMethodParameters(method, args, true, context);

                // 调用方法
                Object result = method.invoke(target, processedArgs);

                // 处理返回值的加密
                if (method.isAnnotationPresent(Encrypt.class)) {
                    result = processReturnValue(result, method, context);
                }

                return ProcessingResult.success("Method encryption processed successfully");

            } catch (Exception e) {
                return ProcessingResult.failure("Failed to process method encryption: " + e.getMessage(), e);
            }
        }

        /**
         * 处理解密
         */
        public ProcessingResult processDecryption(Object target, String methodName,
                                                     Object[] args, EncryptionContext context) {
            Method method = decryptMethods.get(methodName);
            if (method == null) {
                return ProcessingResult.success("No decryption annotation found for method: " + methodName);
            }

            try {
                // 处理方法参数的解密
                Object[] processedArgs = processMethodParameters(method, args, false, context);

                // 调用方法
                Object result = method.invoke(target, processedArgs);

                // 处理返回值的解密
                if (method.isAnnotationPresent(Decrypt.class)) {
                    result = processReturnValue(result, method, context);
                }

                return ProcessingResult.success("Method decryption processed successfully");

            } catch (Exception e) {
                return ProcessingResult.failure("Failed to process method decryption: " + e.getMessage(), e);
            }
        }

        /**
         * 处理方法参数
         */
        private Object[] processMethodParameters(Method method, Object[] args, boolean encrypt,
                                                   EncryptionContext context) {
            Parameter[] parameters = method.getParameters();
            Object[] processedArgs = new Object[parameters.length];

            for (int i = 0; i < parameters.length; i++) {
                Parameter param = parameters[i];
                Object arg = args[i];

                if (arg != null) {
                    if (encrypt && param.isAnnotationPresent(Encrypt.class)) {
                        // 加密参数
                        Encrypt annotation = param.getAnnotation(Encrypt.class);
                        processedArgs[i] = encryptParameter(arg, annotation, context);
                    } else if (!encrypt && param.isAnnotationPresent(Decrypt.class)) {
                        // 解密参数
                        Decrypt annotation = param.getAnnotation(Decrypt.class);
                        processedArgs[i] = decryptParameter(arg, annotation, context);
                    } else {
                        processedArgs[i] = arg;
                    }
                } else {
                    processedArgs[i] = null;
                }
            }

            return processedArgs;
        }

        /**
         * 处理返回值
         */
        private Object processReturnValue(Object returnValue, Method method, EncryptionContext context) {
            if (returnValue == null) {
                return null;
            }

            try {
                if (method.isAnnotationPresent(Encrypt.class)) {
                    Encrypt annotation = method.getAnnotation(Encrypt.class);
                    byte[] encryptedData = encryptValue(returnValue, annotation, context);
                    return Base64.getEncoder().encodeToString(encryptedData);
                } else if (method.isAnnotationPresent(Decrypt.class)) {
                    Decrypt annotation = method.getAnnotation(Decrypt.class);
                    String base64Value = returnValue.toString();
                    byte[] encryptedData = Base64.getDecoder().decode(base64Value);
                    return decryptValue(encryptedData, annotation, context);
                }

                return returnValue;
            } catch (Exception e) {
                throw new EncryptionException("Failed to process return value", e);
            }
        }

        /**
         * 加密参数
         */
        private String encryptParameter(Object param, Encrypt annotation, EncryptionContext context) {
            try {
                Encryptor encryptor = createEncryptor(annotation, context);
                byte[] data = param.toString().getBytes();
                EncryptionResult result = encryptor.encrypt(data, context);
                return Base64.getEncoder().encodeToString(result.getData());
            } catch (Exception e) {
                throw new EncryptionException("Failed to encrypt parameter", e);
            }
        }

        /**
         * 解密参数
         */
        private Object decryptParameter(Object param, Decrypt annotation, EncryptionContext context) {
            try {
                Encryptor encryptor = createEncryptor(annotation, context);
                byte[] encryptedData;
                if (param instanceof byte[]) {
                    encryptedData = (byte[]) param;
                } else {
                    String base64Value = param.toString();
                    encryptedData = Base64.getDecoder().decode(base64Value);
                }
                EncryptionResult result = encryptor.decrypt(encryptedData, context);
                return result.isSuccess() ? new String(result.getData()) : null;
            } catch (Exception e) {
                throw new EncryptionException("Failed to decrypt parameter", e);
            }
        }

        /**
         * 创建加密器
         */
        private Encryptor createEncryptor(Object annotation, EncryptionContext context) {
            if (annotation instanceof Encrypt) {
                Encrypt encrypt = (Encrypt) annotation;
                return EncryptorFactory.getInstance().createEncryptor(encrypt.algorithm(), context);
            } else if (annotation instanceof Decrypt) {
                Decrypt decrypt = (Decrypt) annotation;
                return EncryptorFactory.getInstance().createEncryptor(decrypt.algorithm(), context);
            }
            throw new IllegalArgumentException("Unsupported annotation type: " + annotation.getClass());
        }

        /**
         * 加密值
         */
        private byte[] encryptValue(Object value, Object annotation, EncryptionContext context) {
            try {
                Encryptor encryptor = createEncryptor(annotation, context);
                byte[] data = value.toString().getBytes();
                EncryptionResult result = encryptor.encrypt(data, context);
                return result.isSuccess() ? result.getData() : null;
            } catch (Exception e) {
                throw new EncryptionException("Failed to encrypt value", e);
            }
        }

        /**
         * 解密值
         */
        private Object decryptValue(byte[] encryptedData, Object annotation, EncryptionContext context) {
            try {
                Encryptor encryptor = createEncryptor(annotation, context);
                EncryptionResult result = encryptor.decrypt(encryptedData, context);
                return new String(result.isSuccess() ? result.getData() : new byte[0]);
            } catch (Exception e) {
                throw new EncryptionException("Failed to decrypt value", e);
            }
        }
    }

    /**
     * 处理结果类
     */
    public static class ProcessingResult {

        private final boolean success;
        private final String message;
        private final Exception exception;

        private ProcessingResult(boolean success, String message, Exception exception) {
            this.success = success;
            this.message = message;
            this.exception = exception;
        }

        public static ProcessingResult success(String message) {
            return new ProcessingResult(true, message, null);
        }

        public static ProcessingResult failure(String message) {
            return new ProcessingResult(false, message, null);
        }

        public static ProcessingResult failure(String message, Exception exception) {
            return new ProcessingResult(false, message, exception);
        }

        public boolean isSuccess() {
            return success;
        }

        public String getMessage() {
            return message;
        }

        public Exception getException() {
            return exception;
        }

        @Override
        public String toString() {
            return String.format("ProcessingResult{success=%s, message='%s'}", success, message);
        }
    }
}
